package com.epam.training.concurrency.second.task5;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Random;
import java.util.concurrent.TimeUnit;

/**
 * 
 * @author bogdan
 *
 */
public class Bank {

	private List<Account> accounts = new ArrayList<Account>();
	public final static long TIMEOUT = 100;
	public final static long FIXED_DELAY = 100;

	/**
	 * @throws InterruptedException
	 * 
	 */
	public boolean transfer(Account from, Account to, int amount)
			throws InterruptedException {

		Random rnd = new Random();

		long stopTime = System.nanoTime()
				+ TimeUnit.NANOSECONDS.toNanos(TIMEOUT);

		while (true) {
			if (from.getLock().tryLock()) {
				try {
					if (to.getLock().tryLock()) {
						try {
							if ((from.checkAccount() - amount) <= 0) {
								throw new TransferException(
										"Can`t transfer money");
							} else {
								from.withdraw(amount);
								to.deposit(amount);
							}

							return true;
						} finally {
							to.getLock().unlock();
						}
					}
				} finally {
					from.getLock().unlock();
				}
			}

			if (System.nanoTime() > stopTime) {
				return false;
			}

			TimeUnit.NANOSECONDS.sleep(FIXED_DELAY + rnd.nextLong() % TIMEOUT);
		}
	}

	/**
	 * Add new account
	 */
	public void add(Account account) {
		accounts.add(account);
	}

	public Iterator<Account> iterator() {
		return accounts.iterator();
	}

	public Account get(int i) {
		return accounts.get(i);
	}

	public int size() {
		return accounts.size();
	}
}
